home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 10868 / 10868.xpi / modules / ext / Sync.js < prev   
Text File  |  2010-02-02  |  7KB  |  216 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Weave.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla.
  17.  * Portions created by the Initial Developer are Copyright (C) 2009
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *   Edward Lee <edilee@mozilla.com>
  22.  *   Dan Mills <thunder@mozilla.com>
  23.  *   Myk Melez <myk@mozilla.org>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. let EXPORTED_SYMBOLS = ["Sync"];
  40.  
  41. const Cc = Components.classes;
  42. const Ci = Components.interfaces;
  43. const Cr = Components.results;
  44. const Cu = Components.utils;
  45.  
  46. // Define some constants to specify various sync. callback states
  47. const CB_READY = {};
  48. const CB_COMPLETE = {};
  49. const CB_FAIL = {};
  50.  
  51. // Share a secret only for functions in this file to prevent outside access
  52. const SECRET = {};
  53.  
  54. /**
  55.  * Check if the app is ready (not quitting)
  56.  */
  57. function checkAppReady() {
  58.   // Watch for app-quit notification to stop any sync. calls
  59.   let os = Cc["@mozilla.org/observer-service;1"].
  60.     getService(Ci.nsIObserverService);
  61.   os.addObserver({
  62.     observe: function observe() {
  63.       // Now that the app is quitting, make checkAppReady throw
  64.       checkAppReady = function() {
  65.         throw Components.Exception("App. Quitting", Cr.NS_ERROR_ABORT);
  66.       };
  67.       os.removeObserver(this, "quit-application");
  68.     }
  69.   }, "quit-application", false);
  70.  
  71.   // In the common case, checkAppReady just returns true
  72.   return (checkAppReady = function() true)();
  73. };
  74.  
  75. /**
  76.  * Create a callback that remembers state like whether it's been called
  77.  */
  78. function makeCallback() {
  79.   // Initialize private callback data to prepare to be called
  80.   let _ = {
  81.     state: CB_READY,
  82.     value: null
  83.   };
  84.  
  85.   // The main callback remembers the value it's passed and that it got data
  86.   let onComplete = function makeCallback_onComplete(data) {
  87.     _.state = CB_COMPLETE;
  88.     _.value = data;
  89.   };
  90.  
  91.   // Only allow access to the private data if the secret matches
  92.   onComplete._ = function onComplete__(secret) secret == SECRET ? _ : {};
  93.  
  94.   // Allow an alternate callback to trigger an exception to be thrown
  95.   onComplete.throw = function onComplete_throw(data) {
  96.     _.state = CB_FAIL;
  97.     _.value = data;
  98.  
  99.     // Cause the caller to get an exception and stop execution
  100.     throw data;
  101.   };
  102.  
  103.   return onComplete;
  104. }
  105.  
  106. /**
  107.  * Make a synchronous version of the function object that will be called with
  108.  * the provided thisArg.
  109.  *
  110.  * @param func {Function}
  111.  *        The asynchronous function to make a synchronous function
  112.  * @param thisArg {Object} [optional]
  113.  *        The object that the function accesses with "this"
  114.  * @param callback {Function} [optional] [internal]
  115.  *        The callback that will trigger the end of the async. call
  116.  * @usage let ret = Sync(asyncFunc, obj)(arg1, arg2);
  117.  * @usage let ret = Sync(ignoreThisFunc)(arg1, arg2);
  118.  * @usage let sync = Sync(async); let ret = sync(arg1, arg2);
  119.  */
  120. function Sync(func, thisArg, callback) {
  121.   return function syncFunc(/* arg1, arg2, ... */) {
  122.     // Grab the current thread so we can make it give up priority
  123.     let thread = Cc["@mozilla.org/thread-manager;1"].getService().currentThread;
  124.  
  125.     // Save the original arguments into an array
  126.     let args = Array.slice(arguments);
  127.  
  128.     let instanceCallback = callback;
  129.     // We need to create a callback and insert it if we weren't given one
  130.     if (instanceCallback == null) {
  131.       // Create a new callback for this invocation instance and pass it in
  132.       instanceCallback = makeCallback();
  133.       args.unshift(instanceCallback);
  134.     }
  135.  
  136.     // Call the async function bound to thisArg with the passed args
  137.     func.apply(thisArg, args);
  138.  
  139.     // Keep waiting until our callback is triggered unless the app is quitting
  140.     let callbackData = instanceCallback._(SECRET);
  141.     while (checkAppReady() && callbackData.state == CB_READY)
  142.       thread.processNextEvent(true);
  143.  
  144.     // Reset the state of the callback to prepare for another call
  145.     let state = callbackData.state;
  146.     callbackData.state = CB_READY;
  147.  
  148.     // Throw the value the callback decided to fail with
  149.     if (state == CB_FAIL)
  150.       throw callbackData.value;
  151.  
  152.     // Return the value passed to the callback
  153.     return callbackData.value;
  154.   };
  155. }
  156.  
  157. /**
  158.  * Make a synchronous version of an async. function and the callback to trigger
  159.  * the end of the async. call.
  160.  *
  161.  * @param func {Function}
  162.  *        The asynchronous function to make a synchronous function
  163.  * @param thisArg {Object} [optional]
  164.  *        The object that the function accesses with "this"
  165.  * @usage let [sync, cb] = Sync.withCb(async); let ret = sync(arg1, arg2, cb);
  166.  */
  167. Sync.withCb = function Sync_withCb(func, thisArg) {
  168.   let cb = makeCallback();
  169.   return [Sync(func, thisArg, cb), cb];
  170. };
  171.  
  172. /**
  173.  * Set a timer, simulating the API for the window.setTimeout call.
  174.  * This only simulates the API for the version of the call that accepts
  175.  * a function as its first argument and no additional parameters,
  176.  * and it doesn't return the timeout ID.
  177.  *
  178.  * @param func {Function}
  179.  *        the function to call after the delay
  180.  * @param delay {Number}
  181.  *        the number of milliseconds to wait
  182.  */
  183. function setTimeout(func, delay) {
  184.   let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  185.   let callback = {
  186.     notify: function notify() {
  187.       // This line actually just keeps a reference to timer (prevent GC)
  188.       timer = null;
  189.  
  190.       // Call the function so that "this" is global
  191.       func();
  192.     }
  193.   }
  194.   timer.initWithCallback(callback, delay, Ci.nsITimer.TYPE_ONE_SHOT);
  195. }
  196.  
  197. function sleep(callback, milliseconds) {
  198.   setTimeout(callback, milliseconds);
  199. }
  200.  
  201. /**
  202.  * Sleep the specified number of milliseconds, pausing execution of the caller
  203.  * without halting the current thread.
  204.  * For example, the following code pauses 1000ms between dumps:
  205.  *
  206.  *   dump("Wait for it...\n");
  207.  *   Sync.sleep(1000);
  208.  *   dump("Wait for it...\n");
  209.  *   Sync.sleep(1000);
  210.  *   dump("What are you waiting for?!\n");
  211.  *
  212.  * @param milliseconds {Number}
  213.  *        The number of milliseconds to sleep
  214.  */
  215. Sync.sleep = Sync(sleep);
  216.